# coding=utf8
__author__ = 'lijian'
from packet import Packet
from utils import byteUtil
from utils import bcdUtil

def enum(**enums):
    return type('Enum', (), enums)


class PacketDecode(object):
    STATE = enum(WAIT=1, UID=2, DEP=3, CTRL=4, LEN=5, DATA=6, CS=7, TAIL=8)

    def __init__(self):
        self.state = PacketDecode.STATE.WAIT

        self.stateRecvLen = 0  # 当前状态已接收的字节数
        self.stateNeedLen = 0  # 当前状态应接收字节数
        self.stateRemainLen = 0  # 当前状态剩余应接收字节
        self.stateRecvBytes = []  # 当前状态已接收的字节

        self.reset()


    def reset(self):
        self.frameRaw = []

        self.uid = []
        self.ctrl = 0
        self.dataLen = 0
        self.dataRegion = []
        self.cs = 0

        self.changeSatet(PacketDecode.STATE.WAIT)


    def changeSatet(self, state):
        result = {
            PacketDecode.STATE.WAIT: 1,
            PacketDecode.STATE.UID: 6,
            PacketDecode.STATE.DEP: 1,
            PacketDecode.STATE.CTRL: 1,
            PacketDecode.STATE.LEN: 2,
            PacketDecode.STATE.DATA: self.dataLen,
            PacketDecode.STATE.CS: 1,
            PacketDecode.STATE.TAIL: 1,
        }

        self.state = state
        self.stateRecvLen = 0
        self.stateRecvBytes = []
        self.stateRemainLen = result[state]
        self.stateNeedLen = self.stateRemainLen

    def checkStateData(self, data):
        size, bs = byteUtil.getBytes(data[self.offset:], self.stateRemainLen)
        self.stateRecvLen += size
        self.stateRecvBytes.extend(bs)

        self.offset += size

        if self.stateRecvLen == self.stateNeedLen:
            if self.state != PacketDecode.STATE.WAIT:
                self.frameRaw.extend(self.stateRecvBytes)
            return True
        else:
            self.stateRemainLen -= size
            return False

    def checkTimeOut(self):
        return False

    def checkCS(self):
        return True

    def decode(self, data):
        if not data:
            return None

        self.checkTimeOut()

        self.offset = 0
        while len(data[self.offset:]) > 0:
            if not self.checkStateData(data):
                continue

            if self.state == PacketDecode.STATE.WAIT:
                byte = self.stateRecvBytes[0]
                if byte == 0x68:
                    self.frameRaw = [byte]
                    self.changeSatet(PacketDecode.STATE.UID)
                else:
                    self.reset()
            elif self.state == PacketDecode.STATE.UID:

                self.uid = bcdUtil.bcdTohex(self.stateRecvBytes)

                self.changeSatet(PacketDecode.STATE.DEP)
            elif self.state == PacketDecode.STATE.DEP:
                if self.stateRecvBytes[0] == 0x68:
                    self.changeSatet(PacketDecode.STATE.CTRL)
                else:
                    self.reset()
            elif self.state == PacketDecode.STATE.CTRL:
                self.ctrl = self.stateRecvBytes[0]
                self.changeSatet(PacketDecode.STATE.LEN)
            elif self.state == PacketDecode.STATE.LEN:
                self.dataLen = byteUtil.decodeShortBigEndian(self.stateRecvBytes)
                self.changeSatet(PacketDecode.STATE.DATA)
            elif self.state == PacketDecode.STATE.DATA:
                self.dataRegion = self.stateRecvBytes
                self.changeSatet(PacketDecode.STATE.CS)
            elif self.state == PacketDecode.STATE.CS:
                if self.checkCS():
                    self.cs = self.stateRecvBytes[0]
                    self.changeSatet(PacketDecode.STATE.TAIL)
                else:
                    self.reset()
            elif self.state == PacketDecode.STATE.TAIL:
                if self.stateRecvBytes[0] == 0x16:
                    packet = Packet(self.ctrl, self.dataRegion, self.uid, self.cs, self.frameRaw)
                    self.reset()
                    return packet
                else:
                    self.reset()

        return None
